package jfox.platform;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ejb.EJB;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import jfox.platform.aaa.bo.RoleBO;
import jfox.platform.aaa.bo.UserBO;
import jfox.platform.aaa.entity.Role;
import jfox.platform.aaa.entity.User;
import jfox.platform.aaa.model.UserContext;
import jfox.platform.function.bo.NodeBO;
import jfox.platform.function.entity.Node;
import jfox.platform.infrastructure.SuperAction;
import org.jfox.ejb3.security.JAASLoginRequestCallback;
import org.jfox.ejb3.security.JAASLoginResponseCallback;
import org.jfox.ejb3.security.JAASLoginService;
import org.jfox.framework.annotation.Inject;
import org.jfox.framework.annotation.Service;
import org.jfox.mvc.ActionContext;
import org.jfox.mvc.Invocation;
import org.jfox.mvc.PageContext;
import org.jfox.mvc.SessionContext;
import org.jfox.mvc.annotation.ActionMethod;
import org.jfox.mvc.validate.StringValidation;

/**
 * @author <a href="mailto:yang_y@sysnet.com.cn">Young Yang</a>
 */
@Service(id="login")
public class LoginAction extends SuperAction implements CallbackHandler {

    @Inject
    JAASLoginService loginService;
    

    @EJB
    UserBO userBO;

    @EJB
    RoleBO roleBO;

    @EJB
    NodeBO nodeBO;

    protected boolean hasPermission(ActionContext actionContext) {
        return true;
    }

    /**
     * 登录页面
     */
    @ActionMethod(name="view", successView = "platform/logon.vhtml", httpMethod = ActionMethod.HttpMethod.GET)
    public void logview(ActionContext actionContext) throws Exception {

    }

    /**
     * 登录页面
     */
    @ActionMethod(name="on", successView = "system.today.do", errorView = "platform/logon.vhtml", httpMethod = ActionMethod.HttpMethod.POST, invocationClass = LoginInvocation.class)
    public void logon(ActionContext actionContext) throws Exception {
        LoginInvocation invocation = (LoginInvocation)actionContext.getInvocation();

        User account = (User)loginService.login(actionContext.getSessionContext(), this, invocation.getUsername(),invocation.getPassword());
        if (account == null) {
            String msg = "Invalid username or password. Signon failed";
            PageContext pageContext = actionContext.getPageContext();
            pageContext.setAttribute("errorMessage", msg);
            throw new Exception(msg);
        }
        else {
            // 解析角色和Nodes
            long[] roleIds = account.getRolesArray();
            Set<Role> roles = new HashSet<Role>(roleIds.length);
            Set<Node> nodes = new HashSet<Node>();

            List<Role> allRoles = roleBO.getAllRoles();
            List<Node> allNodes = nodeBO.getAllNodes();
            for(Role role : allRoles){
                if(account.hasRole(role.getId())) {
                    roles.add(role);
                    for(Node node : allNodes){
                        if(role.hasNode(node.getId())) {
                            nodes.add(node);
                        }
                    }
                }
            }

            UserContext userContext = new UserContext(account, roles, nodes);
            SessionContext sessionContext = actionContext.getSessionContext();
            sessionContext.setAttribute(SuperAction.SESSION_USER_KEY, userContext);
        }
    }

    /**
     * 退出
     */
    @ActionMethod(name="off", successView = "platform/logon.vhtml")
    public void logoff(ActionContext actionContext) throws Exception {
        actionContext.destroySessionContext();
    }

    /**
     * 在 doPostEdit 发生异常时，通过该方法设置 PageContext account，
     * 以便跳转到 errorView 时，可以预设数据
     *
     * @param actionContext invocationContext
     */
    protected void doActionFailed(ActionContext actionContext) {

        if(actionContext.getActionMethod().getName().equals("logon")){
/*
            NewAccountInvocation invocation = (NewAccountInvocation)invocationContext.getInvocation();
            Account newAccount = EntityFactory.newEntityObject(Account.class);
            newAccount.setUsername(invocation.getUsername());
            newAccount.setStatus("OK");
            newAccount.setPassword(invocation.getPassword());
            newAccount.setAddress1(invocation.getAddress1());
            newAccount.setAddress2(invocation.getAddress2());
            newAccount.setBannerOption(invocation.getBannerOption());
            newAccount.setCity(invocation.getCity());
            newAccount.setCountry(invocation.getCountry());
            newAccount.setEmail(invocation.getEmail());
            newAccount.setFavouriteCategoryId(invocation.getFavouriteCategoryId());
            newAccount.setFirstName(invocation.getFirstName());
            newAccount.setLanguagePreference(invocation.getLanguagePreference());
            newAccount.setLastName(invocation.getLastName());
            newAccount.setListOption(invocation.getListOption());
            newAccount.setPassword(invocation.getPassword());
            newAccount.setPhone(invocation.getPhone());
            newAccount.setState(invocation.getState());
            newAccount.setZip(invocation.getZip());
            PageContext pageContext = invocationContext.getPageContext();
            pageContext.setAttribute("account", newAccount);
            try {
                doGetNewAccount(invocationContext);
            }
            catch(Exception e) {
                logger.error("doActionFailed error.", e);
            }
*/
        }
    }

    /**
     * JAAS CallbackHandler method
     */
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        JAASLoginRequestCallback requestCallback = (JAASLoginRequestCallback)callbacks[0];
        JAASLoginResponseCallback responseCallback = (JAASLoginResponseCallback)callbacks[1];

        // first parameter is username
        String username = requestCallback.getParams().get(0);
        // second parameter is password
        String password = requestCallback.getParams().get(1);

        User account = userBO.getUserByNameAndPassword(username, password);

        // set callback object, will return by LoginService.login
        responseCallback.setCallbackObject(account);
        // set principal name
        responseCallback.setPrincipalName(username);
        // set role
        responseCallback.setRole(username);
    }

    protected UserContext getUserContext() {
        return new UserContext(userBO.getUnkown(), Collections.EMPTY_LIST, Collections.EMPTY_LIST);
    }

    public static class LoginInvocation extends Invocation {
        @StringValidation(minLength = 4, nullable = false)
        private String username;

        @StringValidation(minLength = 4, nullable = false)
        private String password;

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }
    }
}
